//========================================================================
//  SE5 AI Intelligence - Captain Kwok's Balance Mod v125+
//========================================================================
//
// 1. Determine our defensive spending
// 2. Adjust our offensive spending based on number of enemies and wars
//
// Balance Mod Changes:
// --------------------
// v1.28 Changed - Adjusted spending so AI players will focus
// v1.20 Changed - Added AI support for cooperative intelligence projects
// v1.15 Changed - If the AI is lacking in intel capability it should focus on defense only
//       Changed - Reduced offensive intel spending against neutral players
// v1.12 Changed - AI will focus more intelligence operations against players that have higher priority
//       Changed - Added support for intelligence against alliances
// v1.10 Changed - AI players will no longer use intel points for espionage projects; Only Ministers for human players will
//       Changed - Neutral AI players will not attempt to conduct intelligence
//       Changed - Aggressive and Xenophobic races will sabotage empires that don't have treaties with them
// v1.09 Changed - AI will not attempt any intel if the game is not using intelligence
// v1.07 Changed - Some more adjustments to AI intel spending
// v0.99 Changed - Minor Adjustment to intel spending
//
// Balance Mod To-do List:
// -----------------------
// - Improve intelligence spending distribution (v125+)
//
// Script Function Requests:
// -------------------------
// - Nothing pending

//------------------------------------------------------------------------
// Forward Declarations
//------------------------------------------------------------------------
deffunc

function Set_Intelligence_Spending returns boolean
params
end

enddeffunc

//------------------------------------------------------------------------
// AI_Intelligence
//------------------------------------------------------------------------
function AI_Intelligence returns boolean
vars
begin

  // Set our intelligence spending and focus areas
  if Sys_Using_AI_Minister(sys_long_Player_ID, "Intelligence") and (bool_Intel_Is_Allowed) then
    // Debug Output
    call Sys_Debug_Print("Intel", "-------------")
    call Sys_Debug_Print("Intel", "Intelligence:")
    call Set_Intelligence_Spending()
  endif

  return TRUE
end

//------------------------------------------------------------------------
// Set_Intelligence_Spending
//------------------------------------------------------------------------
function Set_Intelligence_Spending returns boolean
vars
  plr_index:                 long
  num_players:               long
  num_alliances:             long
  num_other_targets:         long
  num_war_targets:           long
  total_pct_against:         long
  intel_pts:                 long
  intel_pts_against:         long
  total_pct:                 long
  def_pct:                   long
  def_pts:                   long
  atk_pct:                   long
  atk_pts:                   long
  atk_pts_plr:               long
  pct_atk_primary:           long := 100
  pct_atk_war:               long
  pct_atk_other:             long
  coop_atk_pct:              long
  coop_def_pct:              long
  spend_amt:                 long
  focus_area_name:           string
  focus_area_id:             long
  focus_pick:                long
  perform_attack:            boolean := TRUE
  perform_espionage:         boolean := FALSE
  perform_sabotage:          boolean := FALSE
  perform_cooperative_atk:   boolean := FALSE
  perform_cooperative_def:   boolean := FALSE
begin

  // Clear our previous intelligence spending
  call Sys_Clear_Empire_Intelligence_Spending_Offense(sys_long_Player_ID)

  // Note the number of players
  set num_players := Sys_Get_Number_Of_Players()

  // Note our total number of intelligence points available
  set intel_pts := Sys_Get_Empire_Current_Points(sys_long_Player_ID, POINT_TYPE_INTELLIGENCE)

  if (intel_pts > 0) then
    // Estimate intelligence spending against us
    if (num_players > 0) then
      for plr_index := 1 to num_players do
        set total_pct_against := Sys_Get_Empire_Intelligence_Spending_Against_Player(plr_index, sys_long_player_ID)
        set intel_pts_against := intel_pts_against + Sys_Divide_Long(total_pct_against * Sys_Get_Empire_Current_Points(plr_index, POINT_TYPE_INTELLIGENCE), 100)
      endfor
    endif

    // Adjust our estimate for the difficulty level; AI on easier levels is more conservative
    case lng_AI_Difficulty
      AI_DIFFICULTY_EASY:
        set intel_pts_against := Sys_Trunc(intel_pts_against * 2.0)
      AI_DIFFICULTY_MEDIUM:
        set intel_pts_against := Sys_Trunc(intel_pts_against * 1.5)
      AI_DIFFICULTY_HARD:
        set intel_pts_against := intel_pts_against
    endcase

    // Use our points for defense only if we are far behind in intel, getting crushed by attack spending or are a neutral player
    if (bool_Enemy_Far_Ahead_In_Intel) or (intel_pts_against > intel_pts * 3) or (bool_Are_We_Neutral_Player) or (lng_AI_Num_of_Priority_Enemies = 0) then
      set def_pct := 100
      set perform_attack := FALSE
    else
      // What percentage of points production do we use for defense?
      if (intel_pts_against > 0) then
        set total_pct_against := Sys_Round(intel_pts_against / intel_pts * 100)
        set def_pct := 1 + total_pct_against
      endif
      // Save some intel points for attack even if our defense percentage is calculated to be higher than 80%
      if (def_pct > 80) then
        set def_pct := 80
      else
        // Set our defense base percentage; Our minimum defense spending is 10%
        set def_pct := Sys_Max_Long(10, def_pct)
      endif
    endif

    // Set our intel initial defense spending
    call Sys_Set_Empire_Intelligence_Defense_Spending(sys_long_Player_ID, def_pct)
    set def_pts := Sys_Trunc(def_pct * intel_pts / 100)
    // Debug output
    call Sys_Debug_Print("Intel", "  - Our Intel Pts = " + Sys_Convert_Long_To_String(intel_pts))
    call Sys_Debug_Print("Intel", "  - Estimated Intel Pts Against = " + Sys_Convert_Long_To_String(intel_pts_against))
    call Sys_Debug_Print("Intel", "  - Estimated Intel Pts to use for Defense = " + Sys_Convert_Long_To_String(def_pts))

    // Perform Intelligence Attack
    if (perform_attack) then
      // How much do we have left to spend on intel attacks?
      set atk_pct := 100 - def_pct
      set atk_pts := Sys_Trunc(atk_pct * intel_pts / 100)
      set atk_pts_plr := Sys_Divide_Long(atk_pts, lng_AI_Num_of_Priority_Enemies)
      // Debug Output
      call Sys_Debug_Print("Intel", "  - Estimated Intel Pts to use for Attack = " + Sys_Convert_Long_To_String(atk_pts))

      // Determine how we will spend our attack points
      if (atk_pct > 0) then
        if (lng_AI_Num_Of_Priority_Enemies > 0) then
          // Don't spread spending against multiple targets if there's not enough attack points to justify it
          if (atk_pts_plr < 500) then
            // All attack spending will be against our primary enemy
            call Sys_Debug_Print("Intel", "    - Concentrate attack versus primary enemy (" + Sys_Empire_Get_Empire_Name(lng_Politics_Primary_Enemy) + ")")
          else
            // Determine how to split our spending if we have enough attack points to spread
            for plr_index := 1 to num_players do
              // Primary enemy
              if (plr_index = lng_Politics_Primary_Enemy) then
                // Debug output
                call Sys_Debug_Print("Intel", "    - Target Primary Enemy (" + Sys_Empire_Get_Empire_Name(plr_index) + ")")
              else
                if (lst_Politics_Target_Player_Priority.get(plr_index) = TARGET_PRIORITY_HIGH) then
                  if Sys_Empire_Politics_At_War_With_Player(sys_long_Player_ID, plr_index) then
                    set num_war_targets := num_war_targets + 1
                    // War targets that are not our primary enemy
                    call Sys_Debug_Print("Intel", "    - Target war enemy (" + Sys_Empire_Get_Empire_Name(plr_index) + ")")
                  else
                    // Other priority enemies that we are not at war with (only if we have lots of attack points to spend)
                    if (atk_pts_plr > 1000) then
                      set num_other_targets := num_other_targets + 1
                      // Debug output
                      call Sys_Debug_Print("Intel", "    - Target non-war priority (" + Sys_Empire_Get_Empire_Name(plr_index) + ")")
                    endif
                  endif
                endif
              endif
            endfor
          endif
        endif
      endif

      // Set attack spending percentages
      if (num_war_targets > 0) and (num_other_targets > 0) then
        // If lots of targets spend only 50% against our primary enemy
        set pct_atk_primary := 50
        // Split remaining 50% weighted against war enemies and other priority targets
        set pct_atk_war := Sys_Round(100 / (2 * num_war_targets + num_other_targets))
        set pct_atk_other := Sys_Round(50 / (2 * num_war_targets + num_other_targets))
        // Debug output
        call Sys_Debug_Print("Intel", "    - Spread attack across all priority enemies")
      else
        // Only primary enemy and war enemies
        if (num_war_targets > 0) and (num_other_targets = 0) then
          // 60% to primary enemy
          set pct_atk_primary := 60
          // 40% across priority war enemies
          set pct_atk_war := Sys_Round(40 / num_war_targets)
          // Debug output
          call Sys_Debug_Print("Intel", "    - Spread attack across primary enemy and priority war enemies")
        else
          // Only non-war 
          if (num_war_targets = 0) and (num_other_targets > 0) then
            // 60% to primary enemy
            set pct_atk_primary := 60
            // 40% across priority non-war enemies
            set pct_atk_other := Sys_Round((40 / num_other_targets))
            // Debug output
            call Sys_Debug_Print("Intel", "    - Spread attack across primary enemy and other non-war priority enemies")
          else
            // Only primary enemy
            set pct_atk_primary := 100
            // Debug output
            call Sys_Debug_Print("Intel", "    - Only attack priority enemy")
          endif
        endif
      endif

      // Determine the focus area for our intelligence operations
      for plr_index := 1 to num_players do
        // Reset variables
        set spend_amt := 0
        set perform_sabotage := FALSE
        set perform_espionage := FALSE
        set perform_cooperative_atk := FALSE
        set perform_cooperative_def := FALSE

        if (plr_index <> sys_long_Player_ID) and Sys_Empire_Politics_Is_Player_Known(sys_long_Player_ID, plr_index) then
          // If we are at war, select sabotage focus areas only
          if Sys_Empire_Politics_At_War_With_Player(sys_long_Player_ID, plr_index) then
            set perform_sabotage := TRUE
          else
            // If we have no treaty, select espionage focus areas only unless we are aggressive or xenophobic
            if Sys_Empire_Politics_Is_Player_Enemy(sys_long_Player_ID, plr_index) then
              if (lng_AI_Categorization >= AI_CATEGORY_AGGRESSIVE) then
                set perform_sabotage := TRUE
              else
                set perform_espionage := TRUE
              endif
            else
              // Do we have a friendly empire we can help with cooperative intelligence
              if (lng_AI_Num_Of_Enemies = 0) or (bool_Enemy_Behind_In_Intel and lng_AI_Num_Of_Enemies < 2) or (lst_AI_Give_Intel_Def_Assistance_To_Empire.indexof(plr_index) > 0) then
                // Are we in a situation to supply intelligence points?
                if (lst_Politics_Friendship_Towards_Player.get(plr_index) > 10) then
                  // Cooperative Intelligence - Defense
                  if (Sys_Get_Empire_Current_Points(plr_index, POINT_TYPE_INTELLIGENCE) < Sys_Divide_Long(intel_pts, 2)) then
                     set perform_cooperative_def := TRUE
                  else
                    // Cooperative Intelligence - Attack
                    if (lng_Politics_Primary_Enemy = Sys_Get_AI_Storage_Long(plr_index, 6, 1)) or (lst_AI_Give_Intel_Atk_Assistance_To_Empire.indexof(plr_index) > 0) then
                      set perform_cooperative_atk := TRUE
                    endif
                  endif
                endif
              endif
            endif
          endif
        endif

        // If we are a computer player, don't bother with espionage activities
        if (bool_Are_We_Computer_Player) then
          set perform_espionage := FALSE
        endif

        // Don't waste time with low priority targets
        if (lst_Politics_Target_Player_Priority.get(plr_index) < TARGET_PRIORITY_MEDIUM) then
          set perform_sabotage := FALSE
          set perform_espionage := FALSE
        endif

        // Don't perform intel operations against a player we said that we wouldn't
        if (lst_AI_Temp_Stop_Intel_vs_Empire.indexof(plr_index) > 0) then
          set perform_sabotage := FALSE
          set perform_espionage := FALSE
        endif

        // Determine specific spending for each target
        if (plr_index = lng_Politics_Primary_Enemy) then
          // Our primary enemy
          set spend_amt := Sys_Trunc(atk_pct * pct_atk_primary / 100)
          // Debug output
          call Sys_Debug_Print("Intel", "      - Priority Enemy (" + Sys_Empire_Get_Empire_Name(plr_index) + ")")
        else
          if (lst_Politics_Target_Player_Priority.get(plr_index) = TARGET_PRIORITY_HIGH) then
            if Sys_Empire_Politics_At_War_With_Player(sys_long_Player_ID, plr_index) then
              if (num_war_targets > 0) then
                // Enemies that we are at war with
                set spend_amt := Sys_Trunc(atk_pct * pct_atk_war / 100)
                // Debug output
                call Sys_Debug_Print("Intel", "      - Priority war enemy (" + Sys_Empire_Get_Empire_Name(plr_index) + ")")
              endif
            else
              if (num_other_targets > 0) then
                // Other priority targets
                set spend_amt := Sys_Trunc(atk_pct * pct_atk_other / 100)
                // Debug output
                call Sys_Debug_Print("Intel", "      - Other priority enemy (" + Sys_Empire_Get_Empire_Name(plr_index) + ")")
              endif
            endif
          endif
        endif

        // Pick a focus area to conduct sabotage
        if (perform_sabotage) then
          set focus_pick := Sys_Get_Random_Long(1, 3)
          case focus_pick
            1:
              set focus_area_name := "Sabotage - Ships & Fleets"
            2:
              set focus_area_name := "Sabotage - Planets & Colonies"
            3:
              if (Sys_Get_Random_Long(1, 2) = 1) then
                set focus_area_name := "Sabotage - Empire Wide"
              else
                set focus_area_name := "Sabotage - Political"
              endif
          endcase
        endif

        // Pick a focus area to conduct espionage
        if (perform_espionage) then
          set focus_pick := Sys_Get_Random_Long(1, 4)
          case focus_pick
            1:
              set focus_area_name := "Espionage - Ships & Fleets"
            2:
              set focus_area_name := "Espionage - Planets & Colonies"
            3:
              set focus_area_name := "Espionage - Empire Wide"
            4:
              set focus_area_name := "Espionage - Political"
          endcase
        endif

        // Pick an area for cooperative intelligence
        if (perform_cooperative_atk) then
          set spend_amt := 10
          set focus_area_name := "Cooperative Intelligence - Attack"
        endif
        // Cooperative - Defense
        if (perform_cooperative_def) then
          set spend_amt := 10
          set focus_area_name := "Cooperative Intelligence - Defense"
        endif

        // Set our focus area and spending level versus the player
        set focus_area_id := Sys_Get_Empire_Intelligence_Focus_Area_ID(focus_area_name)
        call Sys_Set_Empire_Intelligence_Spending_Against_Player(sys_long_Player_ID, plr_index, spend_amt)
        call Sys_Set_Empire_Intelligence_Focus_Area_Against_Player(sys_long_Player_ID, plr_index, focus_area_id)
        set atk_pts := Sys_Trunc(spend_amt * intel_pts / 100)
        // Debug output
        if (focus_area_name <> "") and (atk_pts > 0) and (plr_index <> sys_long_Player_ID) then
          call Sys_Debug_Print("Intel", "        - Spending " + Sys_Convert_Long_To_String(atk_pts) " intel pts (" + Sys_Convert_Long_To_String(spend_amt) + "%) in (" + focus_area_name + ")")
        endif
      endfor
    endif
  endif

  // Add remaining intelligence points to our defense spending
  set total_pct := Sys_Get_Empire_Intelligence_Total_Intel_Spending_Pct(sys_long_Player_ID)

  if (total_pct < 100) then
    set def_pct := def_pct + (100 - Sys_Get_Empire_Intelligence_Total_Intel_Spending_Pct(sys_long_Player_ID))
    set def_pct := Sys_Min_Long(def_pct, 100)
    set def_pts := Sys_Trunc(def_pct / 100 * intel_pts)
    call Sys_Set_Empire_Intelligence_Defense_Spending(sys_long_Player_ID, def_pct)
  endif
  // Debug output
  call Sys_Debug_Print("Intel", "  - Actual Intel pts for defense = " + Sys_Convert_Long_To_String(def_pts))

  return TRUE
end

//------------------------------------------------------------------------